/*
 * Copyright (c) www.bugull.com
 */

package com.bugull.farm.device.server.handler;

import java.net.InetAddress;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import com.bugull.farm.core.cache.PropertiesCache;
import com.bugull.farm.core.enums.EventType;
import com.bugull.farm.core.server.ZKClient;
import com.bugull.farm.core.store.OnOffLineEventHistory;
import com.bugull.farm.device.server.cache.DeviceCache;
import com.bugull.farm.core.store.Device;
import com.bugull.farm.core.utils.ByteUtil;
import com.bugull.mongo.BuguDao;
import com.bugull.mongo.cache.DaoCache;
import com.bugull.redis.RedisConnection;
import com.bugull.redis.mq.MQClient;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelId;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 *
 * @author Frank Wen(xbwen@hotmail.com)
 */
public class DeviceChannelStatusHandler extends ChannelInboundHandlerAdapter {
    
    
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
    	
    	PropertiesCache props = PropertiesCache.getInstance();
        //decrease the channel count
        ZKClient.getInstance().decreaseChannelCount(props.get("zk.device.workers"));
        
        //remove cache data
        ChannelId channelId = ctx.channel().id();
        DeviceCache cache = DeviceCache.getInstance();
        String mac = cache.getMac(channelId);
        if(mac != null){
        	//根据mac地址和channelId的对应关系进行设备删除
        	//因为可能出现设备重新接入，同一个mac地址对应的channelId被替换了的情况，所以要根据对应关系做删除
        	if(cache.removeDev(mac, channelId)){
        		InetAddress local = InetAddress.getLocalHost();
        		String localIp = local.getHostAddress();
        		BuguDao<Device> dao = DaoCache.getInstance().get(Device.class);
        		//分布式系统中，只操作最后在线IP为本机的记录，防止出现数据错误
        		Device device = dao.query().is("macAddress", mac).is("lastOnlineIp", localIp).result();
        		Map<String, Object> map = new HashMap<>();
        		map.put("online", false);
        		Date last = device.getLastOnlineTime();
                if(last != null){
                    long totalOnlineTime = device.getTotalOnlineTime();
                    long diffTime = System.currentTimeMillis() - last.getTime();
                    map.put("totalOnlineTime", totalOnlineTime + diffTime);
                }
        		dao.update().set(map).execute(device);
        		recodeOffLineEvent(mac);
        		
        		//发送离线通知
         		byte[] macBytes = ByteUtil.parseHexStringToArray(mac);
        		if(macBytes != null && macBytes.length==6){
        			//publish offline message to topic
	                byte[] msg = new byte[19];
	                msg[0] = props.getByte("pv");
	                msg[1] = 0x40; //encrypt=0x40, no_encrypt=0x00
	                msg[2] = macBytes[0]; //mac address
	                msg[3] = macBytes[1];
	                msg[4] = macBytes[2];
	                msg[5] = macBytes[3];
	                msg[6] = macBytes[4];
	                msg[7] = macBytes[5];
	                msg[8] = 7 + 1 + 1 + 1; //len field
	                msg[9] = 0x00;
	                msg[10] = 0x00;
	                msg[11] = 0x00;
	                msg[12] = 0x00;
	                msg[13] = 0x00;
	                msg[14] = 0x00;
	                msg[15] = 0x00;
	                msg[16] = props.getByte("example.online");
	                msg[17] = 0x00;
	                msg[18] = 0x00;
	                MQClient client = RedisConnection.getInstance().getMQClient();
	                client.publish(props.get("redis.topic.app"), msg);
                }
        	}
        }
    }
    
    @Override
    public void channelActive(final ChannelHandlerContext ctx) throws Exception {
    	PropertiesCache props = PropertiesCache.getInstance();
    	//increase channel count
        ZKClient.getInstance().increaseChannelCount(props.get("zk.device.workers"));
        DeviceCache.getInstance().addChannel(ctx.channel());
    }

	/**
	 * 记录上下线事件日志
	 * @param macAddress
	 */
	private void recodeOffLineEvent(String macAddress){
		OnOffLineEventHistory history = new OnOffLineEventHistory();
		history.setCreateTime(new Date());
		history.setMacAddress(macAddress);
		history.setEventType(EventType.OFFLINE.toString());
		BuguDao<OnOffLineEventHistory> dao = DaoCache.getInstance().get(OnOffLineEventHistory.class);
		dao.insert(history);
	}

}
